package domain;

import gui.GuiController;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;

import javax.swing.table.TableModel;

import serializables.ServerStatus;
import serializables.Song;

/**
 * Server class
 * 
 * Represents the server
 * 
 * @access public
 */
public class Server 
{
	
	// Attributen
	private String serverIp;
	private GuiController gc;
	private String hostName = "unknown";
	private static final int PORT = 4445;
	private static final int PLAYLIST_PORT = 4446;
	protected DatagramSocket multicastSocket = null;
	
	private static ServerStatus currentStatus;
	private static SongTableModel songTableModel;
	private MulticastStatusVersionThread multicastStatusVersionThread;
	
	private static List<Song> songs;
	private static DatagramPacket mcListOutPacket;
	private static DatagramSocket multicastPlaylistSocket;
	
	/**
	 * Get server iP
	 * 
	 * @access public
	 * @return String
	 */
	public String getServerIp() 
	{
		return serverIp;
	}

	/**
	 * Sets the server IP
	 * 
	 * @access public
	 * @param serverIp
	 * @return void
	 */
	public void setServerIp(String serverIp) 
	{
		this.serverIp = serverIp;
	}

	/**
	 * Runs the application
	 * 
	 * @access public
	 * @return void
	 */
	public void run()
	{
		// Get server IP
		serverIp = getLocalIpAddress();
		
		//Init songs
		songs = new LinkedList<Song>();
		Song testSong = new Song("Slekke", "Johny Turbo", 180, null, 0);
		songs.add(testSong);
		
		
		//init playlist port
		try {
			multicastPlaylistSocket = new DatagramSocket(PLAYLIST_PORT);
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		// Init GUI
		this.gc = new GuiController(this);
		gc.startGui();
		
		//setup ServerStatus;
		currentStatus = new ServerStatus();
		
		setUpServerSideMulticast();
		setUpCommandReceivingThread();
	
	}

	private void setUpCommandReceivingThread() {
		ReceiveCommandThread rct = new ReceiveCommandThread();
		rct.start();
	}

	/**
	 * Set up serverside multicast
	 * 
	 * @access private
	 * @return void
	 */
	private void setUpServerSideMulticast() {
		sendIpAddressToListeners();
		
		/*try 
		{
			multicastSocket = new DatagramSocket(PORT);
			
		} 
		catch (SocketException e) {
			e.printStackTrace();
		}*/
				
	}
				
	private void sendIpAddressToListeners() {
		try {
			multicastStatusVersionThread = new MulticastStatusVersionThread(PORT,"230.0.0.1");
			multicastStatusVersionThread.start();
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	private static String getLocalIpAddress() {
		try {
			
			String hostName = InetAddress.getLocalHost().getHostName();
			InetAddress addrs[] = InetAddress.getAllByName(hostName);
			String myIp = "UNKNOWN";
			for (InetAddress addr: addrs) {
			System.out.println ("addr.getHostAddress() = " + addr.getHostAddress());
			System.out.println ("addr.getHostName() = " + addr.getHostName());
			System.out.println ("addr.isAnyLocalAddress() = " + addr.isAnyLocalAddress());
			System.out.println ("addr.isLinkLocalAddress() = " + addr.isLinkLocalAddress());
			System.out.println ("addr.isLoopbackAddress() = " + addr.isLoopbackAddress());
			System.out.println ("addr.isMulticastAddress() = " + addr.isMulticastAddress());
			System.out.println ("addr.isSiteLocalAddress() = " + addr.isSiteLocalAddress());
			System.out.println ("");

			hostName = addr.getHostName();
			if (!addr.isLoopbackAddress() && addr.isSiteLocalAddress()) {
			myIp = addr.getHostAddress();
			}
			}
			System.out.println ("\nIP = " + myIp);
			return myIp;
			
		} catch (UnknownHostException e) {
		}
		return null;
	}

	public String getConnectionInfo() {
		String info = "Listening to IP: "+ this.getServerIp() +
				"\nHostname: "+ hostName;
		System.out.print(info);
		return info;
	}

	public static long getServerStatusVersionId() {
		return currentStatus.getVersionId();
	}

	public static ServerStatus getServerStatus() {
		return currentStatus;
	}

	public void testUpdateStatus() {
		currentStatus.setRandomText("dit is random text van server status");
		currentStatus.setNewVersionId();
		
	}

	public static TableModel getSongTableModel() {
		if(songTableModel==null){
			songTableModel = new SongTableModel(songs);
		}
		return songTableModel;
	}
	
	public static void MulticastPlaylist(){
		
		try {
			if(multicastPlaylistSocket.isClosed()){
				multicastPlaylistSocket = new DatagramSocket(PLAYLIST_PORT);
			}
			ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
			ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(baos));
			oos.flush();
			oos.writeObject(songs);
			oos.flush();
			
			
			byte[] sendBuffer = baos.toByteArray();
			mcListOutPacket = new DatagramPacket(sendBuffer, sendBuffer.length, InetAddress.getByName("230.0.0.1"), PLAYLIST_PORT);
			multicastPlaylistSocket.send(mcListOutPacket);
			System.out.println("send playlist...");
			multicastPlaylistSocket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	
	}

	public static void addSong(Song song) {
		songTableModel.addSong(song);
		MulticastPlaylist();
		
	}

}
